#pragma once
#ifndef __CONSOLE__INCLUDED__HH__
#define __CONSOLE__INCLUDED__HH__

#include <OgreStringConverter.h>
#include <OIS.h>
#include <SdkTrays.h>
#include <boost\function.hpp>
#include "LitPrerequisites.h"
#include "LitGameStateManager.h"

namespace Lit
{
	class String;
	class LIT_API ConsolePrompt : public OgreBites::Label
	{
	public:
		ConsolePrompt(const std::string &name, const std::string &caption, const int width) : OgreBites::Label( name, caption, width ){ mTextArea->setAlignment(Ogre::TextAreaOverlayElement::Left); }
		virtual ~ConsolePrompt(){}
	};
	class LIT_API Console : public Ogre::LogListener
	{
	public:
		typedef boost::function<std::string( Console*, const std::string& )> CommandPFN;

		struct Command{
			Command( const std::string &nam, CommandPFN cmd, const std::string &argz="" ){ name=nam; func=cmd; cmd; args=argz; }
			Command( const Command& rk ){name=rk.name;args=rk.args;func=rk.func;}
			Command& operator = ( const Command& rk ){name=rk.name;args=rk.args;func=rk.func;return *this;}
			
			bool operator<(Command rhs) { return name < rhs.name; }

			std::string					name;
			std::string					args;
			CommandPFN					func;
		};

		static std::map<std::string, std::string>	_registers;
		typedef std::vector<Command>				CommandList;

	protected:
		OgreBites::TextBox *		mText;
		OgreBites::Label *		mPrompt;
		OgreBites::SdkTrayManager * mTray;
		CommandList					mFuncs;
		size_t						mCurrentLine;
		bool						mActive;
		std::string					mLastCommandReturn;
		std::string					mLastCommand;
		
		void messageLogged( const Ogre::String& message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName ){ append( message ); }
	public:
		class Commands
		{
		public:
			static std::string Help( Console*, const std::string &str );
			
			static std::string Clear( Console*, const std::string &str );
			static std::string GetAmbient( Console*, const std::string &str );
			static std::string SetAmbient( Console*, const std::string &str );
			
			static std::string SetCameraPosition( Console*, const std::string &str );
			static std::string GetCameraPosition( Console*, const std::string &str );
			static std::string SetCameraDirection( Console*, const std::string &str );
			static std::string GetCameraDirection( Console*, const std::string &str );
			static std::string HelpCVar( Console*, const std::string &str );
			static std::string Terminate( Console*, const std::string &str );
			static std::string Debug( Console*, const std::string &str );
			static std::string GameState( Console*, const std::string &str );
		};
		friend struct Command;
		friend class Commands;

		Console(Ogre::RenderWindow*,OgreBites::SdkTrayManager * mgr) ;
		~Console();

		String prompt() const;
		void setPrompt( const String &pr );
		void appendPrompt( const String &pr, bool new_line = false );

		void enable( );
		void disable( );
		
		void clear();
		
		std::vector<std::pair<std::string,bool> > lexer(std::string& exp);

		const CommandList& functions() const{ return mFuncs; }
		void setMacro( const std::string &name, const String &value );
		const std::string& macro( const std::string& name, const std::string& defaultVal = "" )  const;

		void analyzeLine( const std::string &line, size_t ln = 0 );
		void analyzeFunction( const std::string &func );
		std::string replaceMacros( const std::string &exp );

		void callCommand( const std::string &name, const std::string &args = "" );
		void analyzePrompt( );
		void append( const std::string &str );

		bool isActive( ) const;
		void setActive( bool state );

		void injectMousePressed( OIS::Mouse * kb, const OIS::MouseEvent& evt );
		void injectMouseReleased( OIS::Mouse * mz, const OIS::MouseEvent& evt );
		void injectMouseMoved( OIS::Mouse * kb, const OIS::MouseEvent& evt );
		void injectKeyPressed( OIS::Keyboard * kb, const OIS::KeyEvent& evt );
		void injectKeyReleased( OIS::Keyboard * kb, const OIS::KeyEvent& evt );
	};
};
#endif